/***************************************************************************************************
  *Copyright(C),2015-2020,Sumscope
  *FileName	    :  NatDebtDataModel
  *Author	    :  Givins.zhu
  *Version	    :  1.0
  *Date		    :  2015/08/19
  *Desc		    :  data model
  *Function     :  
  *History	    :  
  *Email        :  Givins.zhu@sumscope.com  
  *Requirement  :  
***************************************************************************************************/
#pragma once
#include <bondlib/BondContainer.h>
#include <list>
#include <bondlib/SSCTDTools.h>
#include <bondlib/SSVContainer.h>
#include <bondlib/BondMarketStream.h>
#include <QDateTime>
#include <core/time/date.h>
#include <qbprotocol/include/SSIDBModel.h>
#include <map>
#include <vector>
#include "tfBondInfo.h"
#include <qbcalculator/Calculator.h>
#include <qbcalculator/include/SSBasicCalculationPage.h>
#include <core/strings/string_util.h>
//#include "..\natkline\DlgCmpRTGraphics.h"

#define  NAT_DEBT_ERROR_NUMBER (-999.00)

int TimeToMinutInt(time_t tTm); //转换为一天的时分秒
int AutoTimeToDM(time_t tTm); //自动转换,不是今天则转换为日期,否者转换为时分秒
void TransformCFETSDeal(const xSingleBondQuotationAck_c& ackIn, xQBMarketStreamUnit_c& unitOut);
bool VerifyValidCalculate(double data, bool bNeedZero = true/*是否需要0,在计算值里面需要0值*/); //判断计算数据的有效性
time_t GetBondEstTime(const char * cBondKey, std::string& strEstPrc); //获取中债估值时间
std::string GetClearDay();
// int CALLBACK BasisSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);//基差排序

//记录闪烁位置
typedef struct tagPosition{
	int row;
	int col;
	int time;//闪动次数
	//QColor clrColr;//初始颜色
	float rReduce;//红色每次变化
	float gReduce;//...
	float bReduce;//...
	QString strInstrumentID;
	const bool operator == (const tagPosition& obj) const  
	{  
		if(strInstrumentID == obj.strInstrumentID && col == obj.col/* && time == obj.time*/)
			return true;
		return false;
	} 
}StPosition;

/*国债期货所有K线数据*/
class CNatTFKData{//国债期货K线数据
public:
	virtual ~CNatTFKData();
	//map<QString/*TFID*/,CBondData*> m_mapKData;
	//map<QString, std::list<CCFLOWINFOUNIT>> m_mapTFCCList;//连续合约list
	void Clear();//清除所有数据
	//bool GetTFBondData(const QString& strTFID,CBondData*& bondData,bool bNeedNew = false/*没有找到是否需要new*/);	
	//bool GetTFBondDataTFCC(CDlgCmpRTGraphics*& pGraphics,const QString& strTFID, CBondData*& bondData, bool bNeedNew = false/*没有找到是否需要new*/);//连续合约
};

//CFETS 和交易所 成交信息
class CNatDebtCEDeal{
public:
	std::list<MarketStreamInfo> m_list;
	std::map<std::string/*bondkey*/, xSingleBondQuotationAck_c> m_mapCFETSDeal;//CFETS成交
public:
	bool Clear();
	bool InsertData(xQBMarketStreamList_c* pLstdata);
	bool InsertData(xSingleBondQuotationAck_c* pLstdata);
	void InsetUnitData(const xQBMarketStreamUnit_c& unit);

	bool GetMarketStreamByKey(const char * szBondKey, const char * szBroker, MarketInfo &stInfo);
	bool GetMarketStreamByKey(const char * szBondKey, const char * szListMarket,const char * szBroker, MarketInfo &stInfo);
	bool IsNationalBond(const char* key, const char * market);//是不是国债
protected:
	bool Insert(MarketStreamInfo &info);
};

/*国债期货快照行情*/
class xQBTFPriceUnit_connect : public xQBTFPriceUnit_c{
public:
	xQBTFPriceUnit_connect(){
		InitialParam();
	}
	xQBTFPriceUnit_connect(const xQBTFPriceUnit_connect& obj){

		m_bConnect = obj.m_bConnect;
		m_bSpetialDate = obj.m_bSpetialDate;
		FIELDCOPY(m_cConnectName,obj.m_cConnectName);
		FIELDCOPY(m_cConnectCKey,obj.m_cConnectCKey);
		FIELDCOPY(m_cConnectID,obj.m_cConnectID);
		FIELDCOPY(m_cCurrentTFID,obj.m_cCurrentTFID);
		FIELDCOPY(m_cForeTFID,obj.m_cForeTFID);

		m_LastPrice = obj.m_LastPrice;
		m_PreSettlementPrice = obj.m_PreSettlementPrice;
		m_PreClosePrice = obj.m_PreClosePrice;
		m_PreOpenInterest = obj.m_PreOpenInterest;
		m_OpenPrice = obj.m_OpenPrice;
		m_HighestPrice = obj.m_HighestPrice;
		m_LowestPrice = obj.m_LowestPrice;
		m_Volume = obj.m_Volume;
		m_Turnover = obj.m_Turnover;
		m_LastVolume = obj.m_LastVolume;
		m_IncrementVolume = obj.m_IncrementVolume;
		m_IncrementTurnover = obj.m_IncrementTurnover;;
		m_IncrementOpenInterest = obj.m_IncrementOpenInterest;
		m_LastTurnover = obj.m_LastTurnover;
		m_OpenInterest = obj.m_OpenInterest;
		m_ClosePrice = obj.m_ClosePrice;
		m_SettlementPrice = obj.m_SettlementPrice;
		m_UpperLimitPrice = obj.m_UpperLimitPrice;
		m_LowerLimitPrice = obj.m_LowerLimitPrice;
		m_CurrDelta = obj.m_CurrDelta;
		m_PreDelta = obj.m_PreDelta;
		m_UpdateMillisec = obj.m_UpdateMillisec;
		m_AveragePrice = obj.m_AveragePrice;
		m_BidPrice1 = obj.m_BidPrice1;
		m_BidVolume1 = obj.m_BidVolume1;
		m_AskPrice1 = obj.m_AskPrice1;
		m_AskVolume1 = obj.m_AskVolume1;
		m_BidPrice2 = obj.m_BidPrice2;
		m_BidVolume2 = obj.m_BidVolume2;
		m_AskPrice2 = obj.m_AskPrice2;
		m_AskVolume2 = obj.m_AskVolume2;
		m_BidPrice3 = obj.m_BidPrice3;;
		m_BidVolume3 = obj.m_BidVolume3;
		m_AskPrice3 = obj.m_AskPrice3;
		m_AskVolume3 = obj.m_AskVolume3;
		m_BidPrice4 = obj.m_BidPrice4;
		m_BidVolume4 = obj.m_BidVolume4;
		m_AskPrice4 = obj.m_AskPrice4;
		m_AskVolume4 = obj.m_AskVolume4;
		m_BidPrice5 = obj.m_BidPrice5;
		m_BidVolume5 = obj.m_BidVolume5;
		m_AskPrice5 = obj.m_AskPrice5;
		m_AskVolume5 = obj.m_AskVolume5;
		m_IsHoliday	 = obj.m_IsHoliday;
		FIELDCOPY(m_TradingDay,obj.m_TradingDay);
		FIELDCOPY(m_InstrumentID,obj.m_InstrumentID);
		FIELDCOPY(m_ExchangeID,obj.m_ExchangeID);
		FIELDCOPY(m_ExchangeInstID,obj.m_ExchangeInstID);
		FIELDCOPY(m_UpdateTime,obj.m_UpdateTime);
	}

	xQBTFPriceUnit_connect(const xQBTFPriceUnit_c& obj){
		InitialParam();
		CopyBase(obj);
	}

	void CopyBase( const xQBTFPriceUnit_c &obj ) 
	{
		m_LastPrice = obj.m_LastPrice;
		m_PreSettlementPrice = obj.m_PreSettlementPrice;
		m_PreClosePrice = obj.m_PreClosePrice;
		m_PreOpenInterest = obj.m_PreOpenInterest;
		m_OpenPrice = obj.m_OpenPrice;
		m_HighestPrice = obj.m_HighestPrice;
		m_LowestPrice = obj.m_LowestPrice;
		m_Volume = obj.m_Volume;
		m_Turnover = obj.m_Turnover;
		m_LastVolume = obj.m_LastVolume;
		m_IncrementVolume = obj.m_IncrementVolume;
		m_IncrementTurnover = obj.m_IncrementTurnover;;
		m_IncrementOpenInterest = obj.m_IncrementOpenInterest;
		m_LastTurnover = obj.m_LastTurnover;
		m_OpenInterest = obj.m_OpenInterest;
		m_ClosePrice = obj.m_ClosePrice;
		m_SettlementPrice = obj.m_SettlementPrice;
		m_UpperLimitPrice = obj.m_UpperLimitPrice;
		m_LowerLimitPrice = obj.m_LowerLimitPrice;
		m_CurrDelta = obj.m_CurrDelta;
		m_PreDelta = obj.m_PreDelta;
		m_UpdateMillisec = obj.m_UpdateMillisec;
		m_AveragePrice = obj.m_AveragePrice;
		m_BidPrice1 = obj.m_BidPrice1;
		m_BidVolume1 = obj.m_BidVolume1;
		m_AskPrice1 = obj.m_AskPrice1;
		m_AskVolume1 = obj.m_AskVolume1;
		m_BidPrice2 = obj.m_BidPrice2;
		m_BidVolume2 = obj.m_BidVolume2;
		m_AskPrice2 = obj.m_AskPrice2;
		m_AskVolume2 = obj.m_AskVolume2;
		m_BidPrice3 = obj.m_BidPrice3;;
		m_BidVolume3 = obj.m_BidVolume3;
		m_AskPrice3 = obj.m_AskPrice3;
		m_AskVolume3 = obj.m_AskVolume3;
		m_BidPrice4 = obj.m_BidPrice4;
		m_BidVolume4 = obj.m_BidVolume4;
		m_AskPrice4 = obj.m_AskPrice4;
		m_AskVolume4 = obj.m_AskVolume4;
		m_BidPrice5 = obj.m_BidPrice5;
		m_BidVolume5 = obj.m_BidVolume5;
		m_AskPrice5 = obj.m_AskPrice5;
		m_AskVolume5 = obj.m_AskVolume5;
		m_IsHoliday	 = obj.m_IsHoliday;
		FIELDCOPY(m_TradingDay,obj.m_TradingDay);
		FIELDCOPY(m_InstrumentID,obj.m_InstrumentID);
		FIELDCOPY(m_ExchangeID,obj.m_ExchangeID);
		FIELDCOPY(m_ExchangeInstID,obj.m_ExchangeInstID);
		FIELDCOPY(m_UpdateTime,obj.m_UpdateTime);
	}

	void InitialParam()
	{
		m_bConnect = false;
		m_bSpetialDate = false;
		memset(m_cConnectName, 0, sizeof(m_cConnectName));
		memset(m_cConnectCKey, 0, sizeof(m_cConnectCKey));
		memset(m_cConnectID, 0, sizeof(m_cConnectID));
		memset(m_cCurrentTFID, 0, sizeof(m_cCurrentTFID));
		memset(m_cForeTFID, 0, sizeof(m_cForeTFID));

	}
	//operator xQBTFPriceUnit_c&(){
	//	return *this;
	//}
	
	xQBTFPriceUnit_connect& operator=(xQBTFPriceUnit_c &src)
	{
		CopyBase(src);
		return *this;
	}

	bool operator < (const xQBTFPriceUnit_connect &src) const
	{
		return strcmp(m_cConnectID,src.m_cConnectID) != 0; 
	}
	//xQBTFPriceUnit_connect& operator=(const xQBTFPriceUnit_c &src)
	//{
	//	return *this;
	//}

	bool m_bConnect;				//是否连续合约
	bool m_bSpetialDate;			//是否交割日
	char m_cForeTFID[8];			//上一个合约代码

	char m_cConnectName[65];        //连续合约名字
	char m_cConnectCKey[33];		//连续合约Key
	char m_cConnectID[33];			//连续合约代码
	char m_cCurrentTFID[8];		//对应合约代码
};

//////////成交时间对应的TF价格
class CNatDebtDealTFTmPrc//期货时间点信息
{
public:
	void  InsertTFPrc(time_t tTm , const char* cPrc);//插入价格
	float GetPrc(time_t tTm,std::string& strPrc);//获取时间
	std::map<int,std::string> m_mapPrc;//时间点对应的价格;
};

/*合约交割日以及债券代码*/
class CFutureAKey{
public:
	CFutureAKey(std::string skey,int nDel){
		m_nDelivery = nDel;
		m_Key = skey;
	}

	const bool operator < (const CFutureAKey& obj) const{
		if (m_Key.compare(obj.m_Key) == 0){
			return m_nDelivery < obj.m_nDelivery;
		}
		else{
			return m_Key < obj.m_Key;
		}
	}
	int m_nDelivery;  //期货交割日
	std::string m_Key;//债券Key
};

/*成交和对应TF价格信息*/
class CNatDebtDealTFPrc
{
public:
	CNatDebtDealTFPrc();
	void Clear();//每日清除
	float GetTFPrice(const std::string& strTFId, time_t tTime, std::string& strPrc);//获取合约时间点的价格,1分钟内
	void Initial(std::vector<CFutureInfo>& tf);//初始化合约
	void InsertTFPrc(const std::string& strTFId ,time_t tTime,const char* cPrc);//请求过的数据不用再请求
	void InsertTFPrc(time_t tTime, const char* cPrc);//针对于主动推送
	void InsertTFPrc(xNatDebtDealTFPrc_Req_t* prcReq);//插入TF价格 ,针对主动查询  批量
	/*
		是否已经请求过,防止重新请求
	*/
	bool  HaveReqPrc(const std::string& strTFId , time_t tTime);
	std::map<std::string/*TFID*/,CNatDebtDealTFTmPrc> m_mapInfo;//期货对应的时间点价格。

private:
	int m_nDataDate;//记录成交时间点的日期，如果是同一天，则记录不需要被清除
};

/************************************************************************/
/* 计算隐含率等                                                            */
/************************************************************************/
namespace calcutfRate{
	//计算隐含利率
	class CNatRateParam{
	public:
		CNatRateParam(){
			m_tClearTime = CSSVContainer::GetServerTime();
		}
		double GetTFRateBP(const std::string& strTFID,int nDelivaryDate, const std::string& strCombKey, double dbFac, double dbTFPrc, double dbTFPrcYestoday){
			double dbToday = GetTFRate(strTFID,nDelivaryDate, strCombKey, dbFac, dbTFPrc);
			double dbYestoday = GetTFRate(strTFID,nDelivaryDate, strCombKey, dbFac, dbTFPrcYestoday);
			return (dbToday - dbYestoday) * 100;
		}

		double GetTFRate(const std::string& strTFID, int nDelivaryDate, const std::string& strCombKey, double dbFac, double dbTFPrc){
			if (strTFID.empty()|| nDelivaryDate <= 0 || strCombKey.length() < 4 || dbFac < 0.0001 || dbTFPrc < 0.0001) return NAT_DEBT_ERROR_NUMBER;
			CheckClearData();
			static std::string m_stStrCombRate;
			m_stStrCombRate = qb::base::string_format("%s+%s+%.4f", strTFID.c_str(), strCombKey.c_str(), dbTFPrc);
			if (m_mapRate.find(m_stStrCombRate) != m_mapRate.end()){
				return m_mapRate[m_stStrCombRate];
			}
			std::string strLeft = strCombKey.substr(0, strCombKey.length() - 4);
			time_t tPre = qb::base::IntDate::IntToTime(nDelivaryDate);
			SSCTDTools::GetPreCFFEXTradingDay(tPre);
			QDateTime cTm = QDateTime::fromTime_t(tPre);
			std::string strClean = qb::base::string_format("%4d%02d%02d", cTm.date().year(), cTm.date().month(), cTm.date().day());
			if (dbFac <= 0.001) dbFac = 1;
			double dbPrice = dbTFPrc*dbFac;
			SSBasicCalculationPage ini_sbcp = CSSCalculator::basicPageInitialize(strLeft.c_str(), strClean.c_str());
			SSBasicCalculationPage sbcp = CSSCalculator::cleanPriceToAll(strLeft.c_str(), strClean.c_str(), ini_sbcp.couponRateSpread_, ini_sbcp.indexRate_/**100*/, dbPrice);
			if (VerifyValidCalculate(sbcp.yieldToMaturity_, false)){
				m_mapRate.insert(make_pair(m_stStrCombRate, sbcp.yieldToMaturity_ * 100));
				return sbcp.yieldToMaturity_ * 100;
			}
			return NAT_DEBT_ERROR_NUMBER;
		}

		void CheckClearData(){
			if (CSSVContainer::GetServerTime() - m_tClearTime > 3600){//1小时检查一次
				time_t tServ = CSSVContainer::GetServerTime();
				if (tServ <= 1000 || m_tClearTime <= 1000){
					m_tClearTime = tServ;
				}
				else{
					QDateTime ctServ = QDateTime::fromTime_t(tServ), ctCur = QDateTime::fromTime_t(m_tClearTime);
					if (ctServ.date().day() != ctCur.date().day()){
						m_tClearTime = tServ;
						m_mapRate.clear();
					}
				}
			}
		}

		//V5.3.1需求 计算隐含利率时原逻辑统一使用最新价改为盘前用昨收价，盘中用最新价，盘后用今日收盘价
		static float GetPriceToCalTFRate(const xQBTFPriceUnit_connect& tfPrice) {
			NatTradingPeriod::TradingPeriod tt = NatTradingPeriod::GetNatTradingPeriod();
			if (tt == NatTradingPeriod::TradingPeriod::KPreMarket) {//盘前昨日收盘价
				return tfPrice.m_PreClosePrice;
			} else if (tt == NatTradingPeriod::TradingPeriod::kIntraday) {//盘中最新价
				return tfPrice.m_LastPrice;
			} else {//盘后今日收盘价
				return tfPrice.m_ClosePrice;
			}
		}

		time_t m_tClearTime;//隔天清盘
		map<std::string, double> m_mapRate;
	private:
		class NatTradingPeriod {
		public:
			enum class TradingPeriod : uint8_t {
				KPreMarket = 0, //盘前
				kIntraday,		//盘中
				kAfterhour		//盘后
			};
			static TradingPeriod GetNatTradingPeriod() {
				QDateTime tm = QDateTime::fromTime_t(CSSVContainer::GetServerTime());
				int hhmm = tm.time().hour() * 100 + tm.time().minute();
				if (hhmm >= 800 && hhmm < 930) {
					return TradingPeriod::KPreMarket;
				} else if (hhmm >= 930 && hhmm <= 1515) {
					return TradingPeriod::kIntraday;
				} else {
					return TradingPeriod::kAfterhour;
				}
			}
		};
	};
	CNatRateParam& GetNatRateParam();
}

//国债期货相关的债券  用来传输批量债券信息
class CNatBondAssemble{
public:
	CNatBondAssemble(const char* bondKey){
		PushBond(bondKey);
	}
	CNatBondAssemble(const char* bondKey, const char* listMarket){
		PushBond(bondKey, listMarket);
	}
	CNatBondAssemble(const std::list<TW_BOND> bondList){
		PushBond(bondList);
	}
	CNatBondAssemble(const std::list<xQBRefBond_c> bondList){
		PushBond(bondList);
	}
	//特殊,区分listMarket
	CNatBondAssemble(const std::list<xNatDebtCustomBondUnit_c>& bondList){
		for (auto itr = bondList.begin(); itr != bondList.end(); itr++){
			PushBond(itr->m_List,true);
		}
	}
	void Clear(){
		m_setBond.clear();
		m_lstCIB.clear();
		m_lstExchange.clear();
	}
private:
	void PushBond(const std::list<TW_BOND>&  bondList,bool haveListMkt = false){
		for (auto itr = bondList.begin(); itr != bondList.end(); itr++){
			if (haveListMkt) PushBond(itr->m_BondKey,itr->m_ListedMarket);
			else PushBond(itr->m_BondKey);
		}
	}
	void PushBond(const std::list<xQBRefBond_c>& bondList){
		for (auto itr = bondList.begin(); itr != bondList.end(); itr++){
			PushBond(itr->m_Bond_Key);
		}
	}
	void PushBond(const char* bondKey, const char* listMarket){
		string strBondKey = string(bondKey) + "." + string(listMarket);
		if (m_setBond.find(strBondKey.c_str()) != m_setBond.end()) return;
		TW_BOND bd;
		FIELDCOPY(bd.m_BondKey, bondKey);
		FIELDCOPY(bd.m_ListedMarket, listMarket);
		m_setBond.insert(strBondKey.c_str());
		if (strcmp(listMarket, CBondContainer::lmCIB) == 0){
			m_lstCIB.push_back(bd);
		}
		else if (strcmp(listMarket, CBondContainer::lmSSE) == 0 || strcmp(listMarket, CBondContainer::lmSZE) == 0){
			m_lstExchange.push_back(bd);
		}
	}
	void PushBond(const char* bondKey){
		if (m_setBond.find(bondKey) != m_setBond.end()) return;
		TW_BOND bd;
		FIELDCOPY(bd.m_BondKey, bondKey);
		m_setBond.insert(bondKey);
		FIELDCOPY(bd.m_ListedMarket, CBondContainer::lmCIB);
		m_lstCIB.push_back(bd);
		FIELDCOPY(bd.m_ListedMarket, CBondContainer::lmSSE);
		m_lstExchange.push_back(bd);
		FIELDCOPY(bd.m_ListedMarket, CBondContainer::lmSZE);
		m_lstExchange.push_back(bd);
	}
	
public:
	std::set<std::string> m_setBond;
	std::list<TW_BOND> m_lstCIB, m_lstExchange;
};
